package com.lexi.common.poi.word;

import com.lexi.common.poi.model.WordTableModel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.lexi.common.poi.word.POIElUtil.FOREACH;
import static com.lexi.common.poi.word.POIElUtil.START_STR;

@Slf4j
public class WordPoiUtils {
    private static final BigDecimal bd2 = new BigDecimal("2");
    private static final Pattern TEXT_PATTERN= Pattern.compile("\\{\\{(.*?)\\}\\}");
    private static final Pattern FE_PATTERN= Pattern.compile("\\{\\{fe:(.*?)\\}\\}");
    public static void parseWord(XWPFDocument doc, Map<String, Object> params) throws Exception {
        // 第一步解析文档
        parseParagraphs(doc, params);
        // 第二步解析页眉,页脚
//        parseHeaderAndFoot(doc, map);

        //第四步解析图表
        parseCharts(doc,params);
    }

    /**
     * 处理图表
     * @param doc
     * @param params
     */
    private static <T>void parseCharts(XWPFDocument doc, Map<String, Object> params) {
        for(XWPFChart chart:doc.getCharts()){
            String key=WordChartsUtils.getChartsKey(chart);
            List<T> dataList= (List<T>) params.get(key);
            if(CollectionUtils.isEmpty(dataList)){
                continue;
            }
            key+="_title";
            List<WordTableModel> titleList= (List<WordTableModel>) params.get(key);
            if(CollectionUtils.isEmpty(titleList)){
                continue;
            }
            WordChartsUtils.refreshExcel(chart,dataList,titleList);
            WordChartsUtils.refreshChartCache(chart,dataList,titleList);
        }


    }

    /**
     * 处理段落文字
     *
     * @param doc
     * @throws InvalidFormatException
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static void parseParagraphs(XWPFDocument doc, Map<String,Object> params) throws Exception {
        /**----------------------------处理段落------------------------------------**/
        List<XWPFParagraph> paragraphList = doc.getParagraphs();
        if (paragraphList != null && paragraphList.size() > 0) {
            for (XWPFParagraph paragraph : paragraphList) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    String text = run.getText(0);
                    if (text != null) {
                        if(text.contains(START_STR+FOREACH)){
                            // 动态表格
                            doParseTable(doc, paragraph, run, text,params);
                        }else if(text.contains(START_STR)){
                            doParseText(run, text,params);
                        }

                        //doParseImage(run, text,null);
                        //嵌入文件
                        //doParseEmbeddedObject(run, text,null);
                    }
                }

            }
        }
    }

    private static void doParseText(XWPFRun run, String text, Map<String, Object> textMap) {
        // 替换文本信息
        String tempText = text;
        Matcher matcher =TEXT_PATTERN.matcher(tempText);
        int startIndex=0;
        while(matcher.find(startIndex)){
            String key=matcher.group(1);
            String value=textMap.get(key)==null?"":textMap.get(key).toString();
            tempText=tempText.replaceAll("\\{\\{"+key+"\\}\\}",value);
            startIndex=matcher.end();
        }

        run.setText(tempText, 0);
    }

    private static<T> void doParseTable(XWPFDocument doc, XWPFParagraph paragraph, XWPFRun run, String text,Map params) {
        Matcher matcher=FE_PATTERN.matcher(text);
        String key="";
        List<T> dataList=null;
        List titleList=null;
        String dataRowStr="";
        while(matcher.find()){
            key=matcher.group(1);
            dataList=(List<T>)params.get(key);
            titleList=(List)params.get(key+"_title");
            dataRowStr=(String)params.get(key+"_datarows");
        }
        run.setText("", 0);
        if(CollectionUtils.isEmpty(titleList)){
            log.info("表头集合为空");
            return;
        }
        XmlCursor cursor = paragraph.getCTP().newCursor();
        XWPFTable table = doc.insertNewTbl(cursor);// ---这个是关键
        // 设置表格宽度，第一行宽度就可以了，这个值的单位，目前我也还不清楚，还没来得及研究
        table.setWidth(8500);
        table.setWidth("100%");
        if(StringUtils.isBlank(dataRowStr)){
            List mutiTitleList=new ArrayList();
            mutiTitleList.add(titleList);
            doTableRow(dataList,mutiTitleList,1,table);
        }else{
            int dataRows=Integer.parseInt(dataRowStr);
            doTableRow(dataList,titleList,dataRows,table);
        }
    }

    @SneakyThrows
    private static <T> void doTableRow(List<T> dataList, List titleList, int dataRows, XWPFTable table) {
        //表头部分
        int titleRows=titleList.size();
        XWPFTableRow curTableRow=null;
        List<WordTableModel> curRowTitle=null;
        for(int i=0;i<titleList.size();i++){
            curRowTitle= (List<WordTableModel>) titleList.get(i);
            curTableRow=getRow(table,i);
            for(int j=0;i<curRowTitle.size();j++){
                XWPFTableCell cell=getCell(curTableRow,j);
                WordTableModel model=curRowTitle.get(j);
                setWordCellSelfStyle(cell,model.getTitleColor(),model.getWidth(),model.getMergeHType(),model.getMergeHType(),model.getChnName());
            }
        }
        //数据部分
        if(CollectionUtils.isEmpty(dataList)){
            log.info("数据集合位空");
            return;
        }
        for(int i=0;i<dataList.size();i++){
            //数据对象
            T obj=dataList.get(i);
            curRowTitle= (List<WordTableModel>) titleList.get(titleRows-1-i%dataRows);
            curTableRow=getRow(table,i+titleRows);
            for(int index=0;index<curRowTitle.size();index++){
                XWPFTableCell cell=curTableRow.getCell(index);
                WordTableModel model=curRowTitle.get(index);
                Object objValue=null;
                if(StringUtils.isNotEmpty(model.getAttName())){
                    objValue=obj.getClass().getDeclaredMethod(model.getAttName()).invoke(obj);
                }
                setWordCellSelfStyle(cell,model.getTitleColor(),model.getWidth(),model.getMergeHType(),model.getMergeHType(),objValue);
            }
        }
    }


    /**
     * 设置单元格
     * @param cell
     * @param bgColor
     * @param width
     * @param mergeHType
     * @param mergeVType
     * @param objValue
     */
    private static void setWordCellSelfStyle(XWPFTableCell cell, String bgColor, String width, STMerge.Enum mergeHType, STMerge.Enum mergeVType, Object objValue) {
        setWordCellSelfStyle(cell,"微软雅黑","9",0,"left","top","#000000",bgColor,width,mergeHType,mergeVType,objValue);
    }

    /**
     * 设置表格样式
     *
     * @param cell
     * @param fontName
     * @param fontSize
     * @param fontBlod
     * @param alignment
     * @param vertical
     * @param fontColor
     * @param bgColor
     * @param cellWidth
     * @param value
     */
    public static void setWordCellSelfStyle(XWPFTableCell cell, String fontName, String fontSize, int fontBlod,String alignment, String vertical, String fontColor,String bgColor, String cellWidth, STMerge.Enum mergeHType, STMerge.Enum mergeVType,Object value) {

        String content=value==null?"":value.toString();
        //poi对字体大小设置特殊，不支持小数，但对原word字体大小做了乘2处理
        BigInteger bFontSize = new BigInteger("24");
        if (fontSize != null && !fontSize.equals("")) {
            //poi对字体大小设置特殊，不支持小数，但对原word字体大小做了乘2处理
            BigDecimal fontSizeBD = new BigDecimal(fontSize);
            fontSizeBD = bd2.multiply(fontSizeBD);
            fontSizeBD = fontSizeBD.setScale(0, BigDecimal.ROUND_HALF_UP);//这里取整
            bFontSize = new BigInteger(fontSizeBD.toString());// 字体大小
        }

        // 设置单元格宽度
        cell.setWidth(cellWidth);
        //=====获取单元格
        CTTc tc = cell.getCTTc();
        //====tcPr开始====》》》》
        CTTcPr tcPr = tc.getTcPr();//获取单元格里的<w:tcPr>
        if (tcPr == null) {//没有<w:tcPr>，创建
            tcPr = tc.addNewTcPr();
        }

        //  --vjc开始-->>
        CTVerticalJc vjc = tcPr.getVAlign();//获取<w:tcPr>  的<w:vAlign w:val="center"/>
        if (vjc == null) {//没有<w:w:vAlign/>，创建
            vjc = tcPr.addNewVAlign();
        }
        //设置单元格对齐方式
        vjc.setVal(vertical.equals("top") ? STVerticalJc.TOP : vertical.equals("bottom") ? STVerticalJc.BOTTOM : STVerticalJc.CENTER); //垂直对齐

        CTShd shd = tcPr.getShd();//获取<w:tcPr>里的<w:shd w:val="clear" w:color="auto" w:fill="C00000"/>
        if (shd == null) {//没有<w:shd>，创建
            shd = tcPr.addNewShd();
        }
        // 设置背景颜色
        shd.setFill(bgColor.substring(1));
        //《《《《====tcPr结束====

        //====p开始====》》》》
        CTP p = tc.getPList().get(0);//获取单元格里的<w:p w:rsidR="00C36068" w:rsidRPr="00B705A0" w:rsidRDefault="00C36068" w:rsidP="00C36068">

        //---ppr开始--->>>
        CTPPr ppr = p.getPPr();//获取<w:p>里的<w:pPr>
        if (ppr == null) {//没有<w:pPr>，创建
            ppr = p.addNewPPr();
        }
        //  --jc开始-->>
        CTJc jc = ppr.getJc();//获取<w:pPr>里的<w:jc w:val="left"/>
        if (jc == null) {//没有<w:jc/>，创建
            jc = ppr.addNewJc();
        }
        //设置单元格对齐方式
        jc.setVal(alignment.equals("left") ? STJc.LEFT : alignment.equals("right") ? STJc.RIGHT : STJc.CENTER); //水平对齐
        //  <<--jc结束--
        //  --pRpr开始-->>
        CTParaRPr pRpr = ppr.getRPr(); //获取<w:pPr>里的<w:rPr>
        if (pRpr == null) {//没有<w:rPr>，创建
            pRpr = ppr.addNewRPr();
        }
        CTFonts pfont = pRpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体"/>
        if (pfont == null) {//没有<w:rPr>，创建
            pfont = pRpr.addNewRFonts();
        }
        //设置字体
        pfont.setAscii(fontName);
        pfont.setEastAsia(fontName);
        pfont.setHAnsi(fontName);

        CTOnOff pb = pRpr.getB();//获取<w:rPr>里的<w:b/>
        if (pb == null) {//没有<w:b/>，创建
            pb = pRpr.addNewB();
        }
        //设置字体是否加粗
        pb.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);

        CTHpsMeasure psz = pRpr.getSz();//获取<w:rPr>里的<w:sz w:val="32"/>
        if (psz == null) {//没有<w:sz w:val="32"/>，创建
            psz = pRpr.addNewSz();
        }
        // 设置单元格字体大小
        psz.setVal(bFontSize);
        CTHpsMeasure pszCs = pRpr.getSzCs();//获取<w:rPr>里的<w:szCs w:val="32"/>
        if (pszCs == null) {//没有<w:szCs w:val="32"/>，创建
            pszCs = pRpr.addNewSzCs();
        }
        // 设置单元格字体大小
        pszCs.setVal(bFontSize);
        //  <<--pRpr结束--
        //<<<---ppr结束---

        //---r开始--->>>
        List<CTR> rlist = p.getRList(); //获取<w:p>里的<w:r w:rsidRPr="00B705A0">
        CTR r = null;
        if (rlist != null && rlist.size() > 0) {//获取第一个<w:r>
            r = rlist.get(0);
        } else {//没有<w:r>，创建
            r = p.addNewR();
        }
        //--rpr开始-->>
        CTRPr rpr = r.getRPr();//获取<w:r w:rsidRPr="00B705A0">里的<w:rPr>
        if (rpr == null) {//没有<w:rPr>，创建
            rpr = r.addNewRPr();
        }
        //->-
        CTFonts font = rpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体" w:hint="eastAsia"/>
        if (font == null) {//没有<w:rFonts>，创建
            font = rpr.addNewRFonts();
        }
        //设置字体
        font.setAscii(fontName);
        font.setEastAsia(fontName);
        font.setHAnsi(fontName);

        CTOnOff b = rpr.getB();//获取<w:rPr>里的<w:b/>
        if (b == null) {//没有<w:b/>，创建
            b = rpr.addNewB();
        }
        //设置字体是否加粗
        b.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
        CTColor color = rpr.getColor();//获取<w:rPr>里的<w:color w:val="FFFFFF" w:themeColor="background1"/>
        if (color == null) {//没有<w:color>，创建
            color = rpr.addNewColor();
        }
        // 设置字体颜色
        if (content.contains("↓")) {
            color.setVal("43CD80");
        } else if (content.contains("↑")) {
            color.setVal("943634");
        } else {
            color.setVal(fontColor.substring(1));
        }
        CTHpsMeasure sz = rpr.getSz();
        if (sz == null) {
            sz = rpr.addNewSz();
        }
        sz.setVal(bFontSize);
        CTHpsMeasure szCs = rpr.getSzCs();
        if (szCs == null) {
            szCs = rpr.addNewSz();
        }
        szCs.setVal(bFontSize);
        //-<-
        //<<--rpr结束--
        List<CTText> tlist = r.getTList();
        CTText t = null;
        if (tlist != null && tlist.size() > 0) {//获取第一个<w:r>
            t = tlist.get(0);
        } else {//没有<w:r>，创建
            t = r.addNewT();
        }
        t.setStringValue(content);
        //<<<---r结束---
        if(null!=mergeHType){
            cell.getCTTc().addNewTcPr().addNewHMerge().setVal(mergeHType);
        }
        if(null!=mergeVType){
            cell.getCTTc().addNewTcPr().addNewVMerge().setVal(mergeHType);
        }
    }
    private static XWPFTableRow getRow(XWPFTable table, int rowIndex) {
        XWPFTableRow row=table.getRow(rowIndex);
        if(row==null){
            return table.createRow();
        }
        return row;
    }

    private static XWPFTableCell getCell(XWPFTableRow row, int cellIndex) {
        XWPFTableCell cell=row.getCell(cellIndex);
        if(cell==null){
            return row.createCell();
        }
        return cell;
    }
}
